Completed
Push — patch_1-1-4 ( 3f780f...826343 )
by Emanuele
25:17 queued 11:40
created

IconList.collapseList   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
/*!
2
 * @name      ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
5
 *
6
 * This file contains code covered by:
7
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
8
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
9
 *
10
 * @version 1.1
11
 */
12
13
/**
14
 * This file contains javascript utility functions
15
 */
16
17
var elk_formSubmitted = false,
18
	lastKeepAliveCheck = new Date().getTime(),
19
	ajax_indicator_ele = null;
20
21
// Some very basic browser detection
22
var ua = navigator.userAgent.toLowerCase(),
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
23
	is_opera = !!window.opera, // Opera 8.0-12, past that it behaves like chrome
24
	is_ff = typeof InstallTrigger !== 'undefined' || ((ua.indexOf('iceweasel') !== -1 || ua.indexOf('icecat') !== -1 || ua.indexOf('shiretoko') !== -1 || ua.indexOf('minefield') !== -1) && !is_opera),
0 ignored issues
show
Bug introduced by
The variable InstallTrigger seems to be never declared. If this is a global, consider adding a /** global: InstallTrigger */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
25
	is_safari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0, // Safari 3+
26
	is_chrome = !!window.chrome, // Chrome 1+, Opera 15+
27
	is_ie = !!document.documentMode, // IE8+
28
	is_webkit = ua.indexOf('applewebkit') !== -1;
29
	is_osx = navigator.platform.toUpperCase().indexOf('MAC') >= 0,
0 ignored issues
show
Bug introduced by
The variable is_osx seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.is_osx.
Loading history...
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
30
	is_mobile = navigator.userAgent.indexOf('Mobi') !== -1, // Common mobile including Mozilla, Safari, IE, Opera, Chrome
0 ignored issues
show
Bug introduced by
The variable is_mobile seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.is_mobile.
Loading history...
31
	is_touch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
0 ignored issues
show
Bug introduced by
The variable DocumentTouch seems to be never declared. If this is a global, consider adding a /** global: DocumentTouch */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable is_touch seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.is_touch.
Loading history...
Bug introduced by
Did you forget to assign or call a function?

This error message can for example pop up if you forget to assign the result of a function call to a variable or pass it to another function:

function someFunction(x) {
    (x > 0) ? callFoo() : callBar();
}

// JSHint expects you to assign the result to a variable:
function someFunction(x) {
    var rs = (x > 0) ? callFoo() : callBar();
}

// If you do not use the result, you could also use if statements in the
// case above.
function someFunction(x) {
    if (x > 0) {
        callFoo();
    } else {
        callBar();
    }
}
Loading history...
32
33
// Versions of ie < 9 do not have this built in
34
if (!('getElementsByClassName' in document))
35
{
36
	document.getElementsByClassName = function(className)
37
	{
38
		return $('.' + className);
39
	};
40
}
41
42
/**
43
 * Load an XML document using XMLHttpRequest.
44
 *
45
 * @callback xmlCallback
46
 * @param {string} sUrl
47
 * @param {function} funcCallback
48
 */
49
function getXMLDocument(sUrl, funcCallback)
50
{
51
	var oMyDoc = new XMLHttpRequest(),
0 ignored issues
show
Bug introduced by
The variable XMLHttpRequest seems to be never declared. If this is a global, consider adding a /** global: XMLHttpRequest */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
52
		bAsync = typeof(funcCallback) !== 'undefined',
53
		oCaller = this;
54
55
	if (bAsync)
56
	{
57
		oMyDoc.onreadystatechange = function () {
58
			if (oMyDoc.readyState !== 4)
59
				return;
60
61
			if (oMyDoc.responseXML !== null && oMyDoc.status === 200)
62
				funcCallback.call(oCaller, oMyDoc.responseXML);
63
			else
64
				funcCallback.call(oCaller, false);
65
		};
66
	}
67
68
	oMyDoc.open('GET', sUrl, bAsync);
69
	oMyDoc.send(null);
70
71
	return oMyDoc;
72
}
73
74
/**
75
 * Send a post form to the server using XMLHttpRequest.
76
 *
77
 * @param {string} sUrl
78
 * @param {string} sContent
79
 * @param {string} funcCallback
80
 */
81
function sendXMLDocument(sUrl, sContent, funcCallback)
82
{
83
	var oSendDoc = new window.XMLHttpRequest(),
84
		oCaller = this;
85
86
	if (typeof(funcCallback) !== 'undefined')
87
	{
88
		oSendDoc.onreadystatechange = function () {
89
			if (oSendDoc.readyState !== 4)
90
				return;
91
92
			if (oSendDoc.responseXML !== null && oSendDoc.status === 200)
93
				funcCallback.call(oCaller, oSendDoc.responseXML);
94
			else
95
				funcCallback.call(oCaller, false);
96
		};
97
	}
98
99
	oSendDoc.open('POST', sUrl, true);
100
	if ('setRequestHeader' in oSendDoc)
101
		oSendDoc.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
102
	oSendDoc.send(sContent);
103
104
	return true;
105
}
106
107
/**
108
 * All of our specialized string handling functions are defined here
109
 * php_strtr, php_strtolower, php_urlencode, php_htmlspecialchars
110
 * php_unhtmlspecialchars, php_addslashes, removeEntities, easyReplace
111
 */
112
113
/**
114
 * Character-level replacement function.
115
 * @param {string} sFrom
116
 * @param {string} sTo
117
 */
118
String.prototype.php_strtr = function (sFrom, sTo)
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
119
{
120
	return this.replace(new RegExp('[' + sFrom + ']', 'g'), function (sMatch) {
121
		return sTo.charAt(sFrom.indexOf(sMatch));
122
	});
123
};
124
125
/**
126
 * Simulate PHP's strtolower (in SOME cases PHP uses ISO-8859-1 case folding).
127
 * @returns {String.prototype@call;php_strtr}
128
 */
129
String.prototype.php_strtolower = function ()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
130
{
131
	return typeof(elk_iso_case_folding) === 'boolean' && elk_iso_case_folding === true ? this.php_strtr(
0 ignored issues
show
Bug introduced by
The variable elk_iso_case_folding seems to be never declared. If this is a global, consider adding a /** global: elk_iso_case_folding */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
132
		'ABCDEFGHIJKLMNOPQRSTUVWXYZ\x8a\x8c\x8e\x9f\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde',
133
		'abcdefghijklmnopqrstuvwxyz\x9a\x9c\x9e\xff\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe'
134
	) : this.php_strtr('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
135
};
136
137
/**
138
 * Simulate php's urlencode function
139
 */
140
String.prototype.php_urlencode = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
141
{
142
	return encodeURIComponent(this).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
143
};
144
145
/**
146
 * Simulate php htmlspecialchars function
147
 */
148
String.prototype.php_htmlspecialchars = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
149
{
150
	return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
151
};
152
153
/**
154
 * Simulate php unhtmlspecialchars function
155
 */
156
String.prototype.php_unhtmlspecialchars = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
157
{
158
	return this.replace(/&quot;/g, '"').replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&amp;/g, '&');
159
};
160
161
/**
162
 * Simulate php addslashes function
163
 */
164
String.prototype.php_addslashes = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
165
{
166
	return this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
167
};
168
169
/**
170
 * Callback function for the removeEntities function
171
 */
172
String.prototype._replaceEntities = function(sInput, sDummy, sNum)
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
173
{
174
	return String.fromCharCode(parseInt(sNum));
175
};
176
177
/**
178
 * Removes entities from a string and replaces them with a character code
179
 */
180
String.prototype.removeEntities = function()
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
181
{
182
	return this.replace(/&(amp;)?#(\d+);/g, this._replaceEntities);
183
};
184
185
/**
186
 * String replace function, searches a string for x and replaces it with y
187
 *
188
 * @param {object} oReplacements object of search:replace terms
189
 */
190
String.prototype.easyReplace = function (oReplacements)
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type String. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
191
{
192
	var sResult = this;
193
194
	for (var sSearch in oReplacements) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
195
		sSearch = sSearch.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
196
		sResult = sResult.replace(new RegExp('%' + sSearch + '%', 'g'), oReplacements[sSearch]);
197
	}
198
199
	return sResult;
200
};
201
202
/**
203
 * Simulate php str_repeat function
204
 *
205
 * @param {string} sString
206
 * @param {int} iTime
207
 */
208
function php_str_repeat(sString, iTime)
209
{
210
	if (iTime < 1)
211
		return '';
212
	else
213
		return sString + php_str_repeat(sString, iTime - 1);
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
214
}
215
216
/**
217
 * Opens a new window
218
 *
219
 * @param {string} desktopURL
220
 * @param {int} alternateWidth
221
 * @param {int} alternateHeight
222
 * @param {boolean} noScrollbars
223
 */
224
function reqWin(desktopURL, alternateWidth, alternateHeight, noScrollbars)
225
{
226
	if ((alternateWidth && self.screen.availWidth * 0.8 < alternateWidth) || (alternateHeight && self.screen.availHeight * 0.8 < alternateHeight))
0 ignored issues
show
Bug introduced by
The variable self seems to be never declared. If this is a global, consider adding a /** global: self */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
227
	{
228
		noScrollbars = false;
229
		alternateWidth = Math.min(alternateWidth, self.screen.availWidth * 0.8);
230
		alternateHeight = Math.min(alternateHeight, self.screen.availHeight * 0.8);
231
	}
232
	else
233
		noScrollbars = typeof(noScrollbars) === 'boolean' && noScrollbars === true;
234
235
	window.open(desktopURL, 'requested_popup', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=' + (noScrollbars ? 'no' : 'yes') + ',width=' + (alternateWidth ? alternateWidth : 480) + ',height=' + (alternateHeight ? alternateHeight : 220) + ',resizable=no');
236
237
	// Return false so the click won't follow the link ;).
238
	return false;
239
}
240
241
/**
242
 * Open a overlay div on the screen
243
 *
244
 * @param {string} desktopURL
245
 * @param {string} [sHeader]
246
 * @param {string} [sIcon]
247
 */
248
function reqOverlayDiv(desktopURL, sHeader, sIcon)
249
{
250
	// Set up our div details
251
	var sAjax_indicator = '<div class="centertext"><i class="icon icon-spin icon-big i-spinner"></i></div>';
252
253
	sIcon = typeof(sIcon) === 'string' ? sIcon : 'i-help';
254
	sHeader = typeof(sHeader) === 'string' ? sHeader : help_popup_heading_text;
0 ignored issues
show
Bug introduced by
The variable help_popup_heading_text seems to be never declared. If this is a global, consider adding a /** global: help_popup_heading_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
255
256
	// Create the div that we are going to load
257
	var oContainer = new smc_Popup({heading: sHeader, content: sAjax_indicator, icon: sIcon}),
258
		oPopup_body = $('#' + oContainer.popup_id).find('.popup_content');
259
260
	// Load the help page content (we just want the text to show)
261
	$.ajax({
262
		url: desktopURL,
263
		type: "GET",
264
		dataType: "html"
265
	})
266
	.done(function (data, textStatus, xhr) {
0 ignored issues
show
Unused Code introduced by
The parameter textStatus is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter xhr is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
267
		var help_content = $('<div id="temp_help">').html(data).find('a[href$="self.close();"]').hide().prev('br').hide().parent().html();
268
269
		oPopup_body.html(help_content);
270
	})
271
	.fail(function (xhr, textStatus, errorThrown) {
0 ignored issues
show
Unused Code introduced by
The parameter errorThrown is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
272
		oPopup_body.html(textStatus);
273
	});
274
275
	return false;
276
}
277
278
/**
279
 * smc_Popup class.
280
 *
281
 * @param {object} oOptions
282
 */
283
function smc_Popup(oOptions)
284
{
285
	this.opt = oOptions;
286
	this.popup_id = this.opt.custom_id ? this.opt.custom_id : 'elk_popup';
287
	this.show();
288
}
289
290
// Show the popup div & prepare the close events
291
smc_Popup.prototype.show = function ()
292
{
293
	var popup_class = 'popup_window ' + (this.opt.custom_class ? this.opt.custom_class : 'content'),
294
		icon = this.opt.icon ? '<i class="icon ' + this.opt.icon + ' icon-top"></i> ' : '';
295
296
	// Todo: opt.icon should be a string referencing the desired icon. Will require changing all callers.
297
298
	// Create the div that will be shown - max-height added here - essential anyway,
299
	// so better here than in the CSS.
300
	// Mind you, I still haven't figured out why it should be essential. Cargo cult coding FTW. :P
301
	// Create the div that will be shown
302
	$('body').append('<div id="' + this.popup_id + '" class="popup_container"><div class="' + popup_class + '" style="max-height: none;"><h3 class="popup_heading"><a href="javascript:void(0);" class="hide_popup icon i-close" title="Close"></a>' + icon + this.opt.heading + '</h3><div class="popup_content">' + this.opt.content + '</div></div></div>');
303
304
	// Show it
305
	this.popup_body = $('#' + this.popup_id).children('.popup_window');
306
	this.popup_body.parent().fadeIn(300);
307
308
	// Let the css know its now available
309
	this.popup_body.addClass("in");
310
311
	// Trigger hide on escape or mouse click
312
	var popup_instance = this;
313
	$(document).mouseup(function (e) {
314
		if ($('#' + popup_instance.popup_id).has(e.target).length === 0)
315
			popup_instance.hide();
316
	})
317
	.keyup(function(e){
318
		if (e.keyCode === 27)
319
			popup_instance.hide();
320
	});
321
322
	$('#' + this.popup_id).find('.hide_popup').on('click', function (){ return popup_instance.hide(); });
323
324
	return false;
325
};
326
327
// Hide the popup
328
smc_Popup.prototype.hide = function ()
329
{
330
	$('#' + this.popup_id).fadeOut(300, function(){ $(this).remove(); });
331
332
	return false;
333
};
334
335
/**
336
 * Replaces the currently selected text with the passed text.
337
 * Used by topic.js when inserting a quote into the plain text quick reply (not the editor QR)
338
 *
339
 * @param {string} text
340
 * @param {object} oTextHandle
341
 */
342
function replaceText(text, oTextHandle)
343
{
344
	// Standards compliant text range replace.
345
	if ('selectionStart' in oTextHandle)
346
	{
347
		var begin = oTextHandle.value.substr(0, oTextHandle.selectionStart),
348
			end = oTextHandle.value.substr(oTextHandle.selectionEnd),
349
			scrollPos = oTextHandle.scrollTop,
350
			goForward = 0;
351
352
		oTextHandle.value = begin + text + end;
353
		if (oTextHandle.setSelectionRange)
354
		{
355
			oTextHandle.focus();
356
357
			if (is_opera && text.match(/\n/g) !== null)
358
				goForward = text.match(/\n/g).length;
359
360
			oTextHandle.setSelectionRange(begin.length + text.length + goForward, begin.length + text.length + goForward);
361
		}
362
		oTextHandle.scrollTop = scrollPos;
363
	}
364
	// Just put it on the end.
365
	else
366
	{
367
		oTextHandle.value += text;
368
		oTextHandle.focus(oTextHandle.value.length - 1);
369
	}
370
}
371
372
/**
373
 * Checks if the passed input's value is nothing.
374
 *
375
 * @param {string|object} theField
376
 */
377
function isEmptyText(theField)
378
{
379
	var theValue;
380
381
	// Copy the value so changes can be made..
382
	if (typeof(theField) === 'string')
383
		theValue = theField;
384
	else
385
		theValue = theField.value;
386
387
	// Strip whitespace off the left side.
388
	while (theValue.length > 0 && (theValue.charAt(0) === ' ' || theValue.charAt(0) === '\t'))
389
		theValue = theValue.substring(1, theValue.length);
390
391
	// Strip whitespace off the right side.
392
	while (theValue.length > 0 && (theValue.charAt(theValue.length - 1) === ' ' || theValue.charAt(theValue.length - 1) === '\t'))
393
		theValue = theValue.substring(0, theValue.length - 1);
394
395
	return theValue === '';
396
}
397
398
// Only allow form submission ONCE.
399
function submitonce(theform)
0 ignored issues
show
Unused Code introduced by
The parameter theform is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
400
{
401
	elk_formSubmitted = true;
402
}
403
404
function submitThisOnce(oControl, bReadOnly)
405
{
406
	// oControl might also be a form.
407
	var oForm = 'form' in oControl ? oControl.form : oControl,
408
		aTextareas = oForm.getElementsByTagName('textarea');
409
410
	bReadOnly = typeof bReadOnly == 'undefined' ? true : bReadOnly;
411
	for (var i = 0, n = aTextareas.length; i < n; i++)
412
		aTextareas[i].readOnly = bReadOnly;
413
414
	// If in a second the form is not gone, there may be a problem somewhere
415
	// (e.g. HTML5 required attribute), so release the textareas
416
	window.setTimeout(function() {submitThisOnce(oControl, false);}, 1000);
417
	return !elk_formSubmitted;
418
}
419
420
// @deprecated since 1.0 - innerHTML is supported everywhere.
421
function setInnerHTML(oElement, sToValue)
422
{
423
	if (oElement)
424
		oElement.innerHTML = sToValue;
425
}
426
427
function getInnerHTML(oElement)
428
{
429
	if (oElement)
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if oElement is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
430
		return oElement.innerHTML;
431
}
432
433
/**
434
 * Set the "outer" HTML of an element.
435
 *
436
 * @param {HTMLElement} oElement
437
 * @param {string} sToValue
438
 */
439
function setOuterHTML(oElement, sToValue)
440
{
441
	if ('outerHTML' in oElement)
442
		oElement.outerHTML = sToValue;
443
	else
444
	{
445
		var range = document.createRange();
446
		range.setStartBefore(oElement);
447
		oElement.parentNode.replaceChild(range.createContextualFragment(sToValue), oElement);
448
	}
449
}
450
451
/**
452
 * Checks for variable in theArray, returns true or false
453
 *
454
 * @param {string} variable
455
 * @param {string[]} theArray
456
 */
457
function in_array(variable, theArray)
458
{
459
	for (var i in theArray)
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
460
		if (theArray[i] == variable)
461
			return true;
462
463
	return false;
464
}
465
466
/**
467
 * Checks for variable in theArray and returns the array key
468
 *
469
 * @param {string} variable
470
 * @param {Array.} theArray
471
 */
472
function array_search(variable, theArray)
473
{
474
	for (var i in theArray)
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
475
		if (theArray[i] == variable)
476
			return i;
477
478
	return null;
479
}
480
481
/**
482
 * Find a specific radio button in its group and select it.
483
 *
484
 * @param {HTMLInputElement} oRadioGroup
485
 * @param {type} sName
486
 */
487
function selectRadioByName(oRadioGroup, sName)
488
{
489
	if (!('length' in oRadioGroup))
490
		return oRadioGroup.checked = true;
0 ignored issues
show
Bug introduced by
Did you mean to return a conditional instead of an assignment?

This error is thrown if you assign to a variable in your return statement:

function someFunction(x) {
    return x = 1;
}

// Instead you maybe ment

function someFunction(x) {
    return x === 1;
}
Loading history...
491
492
	for (var i = 0, n = oRadioGroup.length; i < n; i++)
493
		if (oRadioGroup[i].value === sName)
494
			return oRadioGroup[i].checked = true;
0 ignored issues
show
Bug introduced by
Did you mean to return a conditional instead of an assignment?

This error is thrown if you assign to a variable in your return statement:

function someFunction(x) {
    return x = 1;
}

// Instead you maybe ment

function someFunction(x) {
    return x === 1;
}
Loading history...
495
496
	return false;
497
}
498
499
/**
500
 * Selects all the form objects with a single click
501
 *
502
 * @param {object} oInvertCheckbox
503
 * @param {object} oForm
504
 * @param {string} sMask
505
 * @param {string} sValue
506
 */
507
function selectAllRadio(oInvertCheckbox, oForm, sMask, sValue)
508
{
509
	for (var i = 0; i < oForm.length; i++)
510
		if (oForm[i].name !== undefined && oForm[i].name.substr(0, sMask.length) == sMask && oForm[i].value == sValue)
511
			oForm[i].checked = true;
512
}
513
514
/**
515
 * Invert all check boxes at once by clicking a single checkbox.
516
 *
517
 * @param {object} oInvertCheckbox
518
 * @param {HTMLFormElement} oForm
519
 * @param {string} [sMask]
520
 * @param {boolean} [bIgnoreDisabled]
521
 */
522
function invertAll(oInvertCheckbox, oForm, sMask, bIgnoreDisabled)
523
{
524
	for (var i = 0; i < oForm.length; i++)
525
	{
526
		if (!('name' in oForm[i]) || (typeof(sMask) === 'string' && oForm[i].name.substr(0, sMask.length) !== sMask && oForm[i].id.substr(0, sMask.length) !== sMask))
527
			continue;
528
529
		if (!oForm[i].disabled || (typeof(bIgnoreDisabled) === 'boolean' && bIgnoreDisabled))
530
			oForm[i].checked = oInvertCheckbox.checked;
531
	}
532
}
533
534
/**
535
 * Keep the session alive - always!
536
 */
537
function elk_sessionKeepAlive()
538
{
539
	var curTime = new Date().getTime();
540
541
	// Prevent a Firefox bug from hammering the server.
542
	if (elk_scripturl && curTime - lastKeepAliveCheck > 900000)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable elk_scripturl is declared in the current environment, consider using typeof elk_scripturl === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
543
	{
544
		var tempImage = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
545
		tempImage.src = elk_prepareScriptUrl(elk_scripturl) + 'action=keepalive;time=' + curTime;
546
		lastKeepAliveCheck = curTime;
547
	}
548
549
	window.setTimeout(function() {elk_sessionKeepAlive();}, 1200000);
550
}
551
window.setTimeout(function() {elk_sessionKeepAlive();}, 1200000);
552
553
/**
554
 * Set a theme option through javascript. / ajax
555
 *
556
 * @param {string} option name being set
557
 * @param {string} value of the option
558
 * @param {string|null} theme its being set or null for all
559
 * @param {string|null} additional_vars to use in the url request that will be sent
560
 */
561
function elk_setThemeOption(option, value, theme, additional_vars)
562
{
563
	if (additional_vars === null || typeof(additional_vars) === 'undefined')
564
		additional_vars = '';
565
566
	var tempImage = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
567
	tempImage.src = elk_prepareScriptUrl(elk_scripturl) + 'action=jsoption;var=' + option + ';val=' + value + ';' + elk_session_var + '=' + elk_session_id + additional_vars + (theme === null ? '' : '&th=' + theme) + ';time=' + (new Date().getTime());
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_session_id seems to be never declared. If this is a global, consider adding a /** global: elk_session_id */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_session_var seems to be never declared. If this is a global, consider adding a /** global: elk_session_var */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
568
}
569
570
/**
571
 * Password hashing for user
572
 *
573
 * @param {type} doForm
574
 * @param {type} cur_session_id
575
 * @param {type} token
576
 */
577
function hashLoginPassword(doForm, cur_session_id, token)
578
{
579
	// Don't have our hash lib available?
580
	if (typeof(hex_sha256) === 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha256 seems to be never declared. If this is a global, consider adding a /** global: hex_sha256 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
581
		return;
582
583
	// Are they using an email address?
584
	if (doForm.user.value.indexOf('@') !== -1)
585
		return;
586
587
	doForm.passwrd.autocomplete = 'off';
588
589
	// Fill in the hidden fields with our sha hash
590
	doForm.hash_passwrd.value = hex_sha256(doForm.user.value.php_strtolower() + doForm.passwrd.value);
591
592
	// If the form also contains the old hash input fill it to smooth transitions
593
	if ('old_hash_passwrd' in doForm && typeof(hex_sha1) !== 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha1 seems to be never declared. If this is a global, consider adding a /** global: hex_sha1 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
594
		doForm.old_hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.php_strtolower() + doForm.passwrd.value) + cur_session_id + (typeof token === 'undefined' ? '' : token));
595
596
	doForm.passwrd.value = doForm.passwrd.value.replace(/./g, '*');
597
}
598
599
/**
600
 * Password hashing for admin login
601
 *
602
 * @param {type} doForm
603
 * @param {type} username
604
 * @param {type} cur_session_id
605
 * @param {type} token
606
 */
607
function hashAdminPassword(doForm, username, cur_session_id, token)
0 ignored issues
show
Unused Code introduced by
The parameter token is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter cur_session_id is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
608
{
609
	// Missing sha256.js?
610
	if (typeof(hex_sha256) === 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha256 seems to be never declared. If this is a global, consider adding a /** global: hex_sha256 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
611
		return;
612
613
	doForm.admin_hash_pass.value = hex_sha256(username.php_strtolower() + doForm.admin_pass.value);
614
	doForm.admin_pass.value = doForm.admin_pass.value.replace(/./g, '*');
615
}
616
617
/**
618
 * Hashing for the moderation login
619
 *
620
 * @param {type} doForm
621
 * @param {type} username
622
 * @param {type} cur_session_id
623
 * @param {type} token
624
 */
625
function hashModeratePassword(doForm, username, cur_session_id, token)
0 ignored issues
show
Unused Code introduced by
The parameter cur_session_id is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter token is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
626
{
627
	// Missing sha256.js?
628
	if (typeof(hex_sha256) === 'undefined')
0 ignored issues
show
Bug introduced by
The variable hex_sha256 seems to be never declared. If this is a global, consider adding a /** global: hex_sha256 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
629
		return;
630
631
	doForm.moderate_hash_pass.value = hex_sha256(username.php_strtolower() + doForm.moderate_pass.value);
632
	doForm.moderate_pass.value = doForm.moderate_pass.value.replace(/./g, '*');
633
}
634
635
/**
636
 * Shows the page numbers by clicking the dots (in compact view).
637
 * @todo @DEPRECATED it is not used. If we don't care about compatibility it can be removed
638
 *
639
 * @param {HTMLElement} spanNode
640
 * @param {string} baseURL
641
 * @param {int} firstPage
642
 * @param {int} lastPage
643
 * @param {int} perPage
644
 */
645
function expandPages(spanNode, baseURL, firstPage, lastPage, perPage)
646
{
647
	var replacement = '',
648
		i = 0,
649
		oldLastPage = 0,
650
		perPageLimit = 50;
651
652
	// Prevent too many pages to be loaded at once.
653
	if ((lastPage - firstPage) / perPage > perPageLimit)
654
	{
655
		oldLastPage = lastPage;
656
		lastPage = firstPage + perPageLimit * perPage;
657
	}
658
659
	// Calculate the new pages.
660
	for (i = firstPage; i < lastPage; i += perPage)
661
		replacement += '<a class="navPages" href="' + baseURL.replace(/%1\$d/, i).replace(/%%/g, '%') + '">' + (1 + i / perPage) + '</a> ';
662
663
	if (oldLastPage > 0)
664
		replacement += '<span class="expand_pages" role="menuitem" onclick="expandPages(this, \'' + baseURL + '\', ' + lastPage + ', ' + oldLastPage + ', ' + perPage + ');"> ... </span> ';
665
666
	// Replace the dots by the new page links.
667
	setOuterHTML(spanNode, replacement);
668
}
669
670
/**
671
 * Used by elk_Toggle to add an image to the swap/toggle array
672
 *
673
 * @param {string} sSrc
674
 */
675
function smc_preCacheImage(sSrc)
676
{
677
	if (!('smc_aCachedImages' in window))
678
		window.smc_aCachedImages = [];
679
680
	if (!in_array(sSrc, window.smc_aCachedImages))
681
	{
682
		var oImage = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
683
		oImage.src = sSrc;
684
	}
685
}
686
687
/**
688
 * smc_Cookie class.
689
 *
690
 * @param {object} oOptions
691
 */
692
function smc_Cookie(oOptions)
693
{
694
	this.opt = oOptions;
695
	this.oCookies = {};
696
	this.init();
697
}
698
699
smc_Cookie.prototype.init = function()
700
{
701
	if ('cookie' in document && document.cookie !== '')
702
	{
703
		var aCookieList = document.cookie.split(';');
704
		for (var i = 0, n = aCookieList.length; i < n; i++)
705
		{
706
			var aNameValuePair = aCookieList[i].split('=');
707
			this.oCookies[aNameValuePair[0].replace(/^\s+|\s+$/g, '')] = decodeURIComponent(aNameValuePair[1]);
708
		}
709
	}
710
};
711
712
smc_Cookie.prototype.get = function(sKey)
713
{
714
	return sKey in this.oCookies ? this.oCookies[sKey] : null;
715
};
716
717
smc_Cookie.prototype.set = function(sKey, sValue)
718
{
719
	document.cookie = sKey + '=' + encodeURIComponent(sValue);
720
};
721
722
/**
723
 * elk_Toggle class.
724
 *
725
 * Collapses a section of the page
726
 * Swaps the collapsed section class or image to indicate the state
727
 * Updates links to indicate state and allow reversal of the action
728
 * Saves state in a cookie and/or in a theme setting option so the last state
729
 * is remembered for the user.
730
 *
731
 * @param {object} oOptions
732
 * @returns {elk_Toggle}
733
 */
734
function elk_Toggle(oOptions)
735
{
736
	this.opt = oOptions;
737
	this.bCollapsed = false;
738
	this.oCookie = null;
739
	this.init();
740
}
741
742
// Initialize the toggle class
743
elk_Toggle.prototype.init = function()
744
{
745
	var i = 0,
746
		n = 0;
747
748
	// The master switch can disable this toggle fully.
749
	if ('bToggleEnabled' in this.opt && !this.opt.bToggleEnabled)
750
		return;
751
752
	// If cookies are enabled and they were set, override the initial state.
753
	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
754
	{
755
		// Initialize the cookie handler.
756
		this.oCookie = new smc_Cookie({});
757
758
		// Check if the cookie is set.
759
		var cookieValue = this.oCookie.get(this.opt.oCookieOptions.sCookieName);
760
		if (cookieValue !== null)
761
			this.opt.bCurrentlyCollapsed = cookieValue === '1';
762
	}
763
764
	// If the init state is set to be collapsed, collapse it.
765
	if (this.opt.bCurrentlyCollapsed)
766
		this.changeState(true, true);
767
768
	// Initialize the images to be clickable.
769
	if ('aSwapImages' in this.opt)
770
	{
771
		for (i = 0, n = this.opt.aSwapImages.length; i < n; i++)
772
		{
773
			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
774
			if (typeof(oImage) === 'object' && oImage !== null)
775
			{
776
				// Display the image in case it was hidden.
777
				if (getComputedStyle(oImage).getPropertyValue("display") === 'none')
778
					oImage.style.display = 'inline';
779
780
				oImage.instanceRef = this;
781
				oImage.onclick = function () {this.instanceRef.toggle();this.blur();};
782
				oImage.style.cursor = 'pointer';
783
784
				// Pre-load the collapsed image.
785
				smc_preCacheImage(this.opt.aSwapImages[i].srcCollapsed);
786
			}
787
		}
788
	}
789
	// No images to swap, perhaps they want to swap the class?
790
	else if ('aSwapClasses' in this.opt)
791
	{
792
		for (i = 0, n = this.opt.aSwapClasses.length; i < n; i++)
793
		{
794
			var oContainer = document.getElementById(this.opt.aSwapClasses[i].sId);
795
			if (typeof(oContainer) === 'object' && oContainer !== null)
796
			{
797
				// Display the image in case it was hidden.
798
				if (getComputedStyle(oContainer).getPropertyValue("display") === 'none')
799
					oContainer.style.display = 'block';
800
801
				oContainer.instanceRef = this;
802
803
				oContainer.onclick = function () {
804
					this.instanceRef.toggle();
805
					this.blur();
806
				};
807
				oContainer.style.cursor = 'pointer';
808
			}
809
		}
810
	}
811
812
	// Initialize links.
813
	if ('aSwapLinks' in this.opt)
814
	{
815
		for (i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
816
		{
817
			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
818
			if (typeof(oLink) === 'object' && oLink !== null)
819
			{
820
				// Display the link in case it was hidden.
821
				if (getComputedStyle(oLink).getPropertyValue("display") === 'none')
822
					oLink.style.display = 'inline-block';
823
824
				oLink.instanceRef = this;
825
				oLink.onclick = function () {
826
					this.instanceRef.toggle();
827
					this.blur();
828
					return false;
829
				};
830
			}
831
		}
832
	}
833
};
834
835
/**
836
 * Collapse or expand the section.
837
 *
838
 * @param {boolean} bCollapse
839
 * @param {boolean} [bInit]
840
 */
841
elk_Toggle.prototype.changeState = function(bCollapse, bInit)
842
{
843
	var i = 0,
844
		n = 0,
845
		oContainer;
846
847
	// Default bInit to false.
848
	bInit = typeof(bInit) !== 'undefined';
849
850
	// Handle custom function hook before collapse.
851
	if (!bInit && bCollapse && 'funcOnBeforeCollapse' in this.opt)
852
	{
853
		this.tmpMethod = this.opt.funcOnBeforeCollapse;
854
		this.tmpMethod();
855
		delete this.tmpMethod;
856
	}
857
	// Handle custom function hook before expand.
858
	else if (!bInit && !bCollapse && 'funcOnBeforeExpand' in this.opt)
859
	{
860
		this.tmpMethod = this.opt.funcOnBeforeExpand;
861
		this.tmpMethod();
862
		delete this.tmpMethod;
863
	}
864
865
	// Loop through all the items that need to be toggled.
866
	if ('aSwapImages' in this.opt)
867
	{
868
		// Swapping images on a click
869
		for (i = 0, n = this.opt.aSwapImages.length; i < n; i++)
870
		{
871
			var oImage = document.getElementById(this.opt.aSwapImages[i].sId);
872
			if (typeof(oImage) === 'object' && oImage !== null)
873
			{
874
				// Only (re)load the image if it's changed.
875
				var sTargetSource = bCollapse ? this.opt.aSwapImages[i].srcCollapsed : this.opt.aSwapImages[i].srcExpanded;
876
				if (oImage.src != sTargetSource)
877
					oImage.src = sTargetSource;
878
879
				oImage.alt = oImage.title = bCollapse ? this.opt.aSwapImages[i].altCollapsed : this.opt.aSwapImages[i].altExpanded;
880
			}
881
		}
882
	}
883
	else if ('aSwapClasses' in this.opt)
884
	{
885
		// Or swapping the classes
886
		for (i = 0, n = this.opt.aSwapClasses.length; i < n; i++)
887
		{
888
			oContainer = document.getElementById(this.opt.aSwapClasses[i].sId);
889
			if (typeof(oContainer) === 'object' && oContainer !== null)
890
			{
891
				// Only swap the class if the state changed
892
				var sTargetClass = bCollapse ? this.opt.aSwapClasses[i].classCollapsed : this.opt.aSwapClasses[i].classExpanded;
893
				if (oContainer.className !== sTargetClass)
894
					oContainer.className = sTargetClass;
895
896
				// And show the new title
897
				oContainer.title = oContainer.title = bCollapse ? this.opt.aSwapClasses[i].titleCollapsed : this.opt.aSwapClasses[i].titleExpanded;
898
			}
899
		}
900
	}
901
902
	// Loop through all the links that need to be toggled.
903
	if ('aSwapLinks' in this.opt)
904
	{
905
		for (i = 0, n = this.opt.aSwapLinks.length; i < n; i++)
906
		{
907
			var oLink = document.getElementById(this.opt.aSwapLinks[i].sId);
908
			if (typeof(oLink) === 'object' && oLink !== null)
909
				oLink.innerHTML = bCollapse ? this.opt.aSwapLinks[i].msgCollapsed : this.opt.aSwapLinks[i].msgExpanded;
910
		}
911
	}
912
913
	// Now go through all the sections to be collapsed.
914
	for (i = 0, n = this.opt.aSwappableContainers.length; i < n; i++)
915
	{
916
		if (this.opt.aSwappableContainers[i] === null)
917
			continue;
918
919
		oContainer = document.getElementById(this.opt.aSwappableContainers[i]);
920
		if (typeof(oContainer) === 'object' && oContainer !== null)
921
		{
922
			if (bCollapse)
923
				$(oContainer).slideUp();
924
			else
925
				$(oContainer).slideDown();
926
		}
927
	}
928
929
	// Update the new state.
930
	this.bCollapsed = bCollapse;
931
932
	// Update the cookie, if desired.
933
	if ('oCookieOptions' in this.opt && this.opt.oCookieOptions.bUseCookie)
934
		this.oCookie.set(this.opt.oCookieOptions.sCookieName, this.bCollapsed ? '1' : '0');
935
936
	if (!bInit && 'oThemeOptions' in this.opt && this.opt.oThemeOptions.bUseThemeSettings)
937
		elk_setThemeOption(this.opt.oThemeOptions.sOptionName, this.bCollapsed ? '1' : '0', 'sThemeId' in this.opt.oThemeOptions ? this.opt.oThemeOptions.sThemeId : null, 'sAdditionalVars' in this.opt.oThemeOptions ? this.opt.oThemeOptions.sAdditionalVars : null);
938
};
939
940
elk_Toggle.prototype.toggle = function()
941
{
942
	// Change the state by reversing the current state.
943
	this.changeState(!this.bCollapsed);
944
};
945
946
/**
947
 * Creates and shows or hides the sites ajax in progress indicator
948
 *
949
 * @param {boolean} turn_on
950
 * @returns {undefined}
951
 */
952
function ajax_indicator(turn_on)
953
{
954
	if (ajax_indicator_ele === null)
955
	{
956
		ajax_indicator_ele = document.getElementById('ajax_in_progress');
957
958
		if (ajax_indicator_ele === null && typeof(ajax_notification_text) !== null)
0 ignored issues
show
Bug introduced by
The variable ajax_notification_text seems to be never declared. If this is a global, consider adding a /** global: ajax_notification_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
959
		{
960
			create_ajax_indicator_ele();
961
		}
962
	}
963
964
	if (ajax_indicator_ele !== null)
965
	{
966
		ajax_indicator_ele.style.display = turn_on ? 'block' : 'none';
967
	}
968
}
969
970
/**
971
 * Creates the ajax notification div and adds it to the current screen
972
 */
973
function create_ajax_indicator_ele()
974
{
975
	// Create the div for the indicator.
976
	ajax_indicator_ele = document.createElement('div');
977
978
	// Set the id so it'll load the style properly.
979
	ajax_indicator_ele.id = 'ajax_in_progress';
980
981
	// Add the image in and link to turn it off.
982
	var cancel_link = document.createElement('a');
983
	cancel_link.href = 'javascript:ajax_indicator(false)';
0 ignored issues
show
Coding Style introduced by
Script urls should not be used.
Loading history...
984
985
	var cancel_img = document.createElement('img');
986
	cancel_img.src = elk_images_url + '/icons/quick_remove.png';
0 ignored issues
show
Bug introduced by
The variable elk_images_url seems to be never declared. If this is a global, consider adding a /** global: elk_images_url */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
987
988
	if (typeof(ajax_notification_cancel_text) !== 'undefined')
0 ignored issues
show
Bug introduced by
The variable ajax_notification_cancel_text seems to be never declared. If this is a global, consider adding a /** global: ajax_notification_cancel_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
989
	{
990
		cancel_img.alt = ajax_notification_cancel_text;
991
		cancel_img.title = ajax_notification_cancel_text;
992
	}
993
994
	// Add the cancel link and image to the indicator.
995
	cancel_link.appendChild(cancel_img);
996
	ajax_indicator_ele.appendChild(cancel_link);
997
998
	// Set the text.  (Note:  You MUST append here and not overwrite.)
999
	ajax_indicator_ele.innerHTML += ajax_notification_text;
0 ignored issues
show
Bug introduced by
The variable ajax_notification_text seems to be never declared. If this is a global, consider adding a /** global: ajax_notification_text */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1000
1001
	// Finally attach the element to the body.
1002
	document.body.appendChild(ajax_indicator_ele);
1003
}
1004
1005
/**
1006
 * Creates and event listener object for a given object
1007
 * Object events can then be added with addEventListener
1008
 *
1009
 * @param {HTMLElement} oTarget
1010
 */
1011
function createEventListener(oTarget)
1012
{
1013
	if (!('addEventListener' in oTarget))
1014
	{
1015
		if (oTarget.attachEvent)
1016
		{
1017
			oTarget.addEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1018
				oTarget.attachEvent('on' + sEvent, funcHandler);
1019
			};
1020
1021
			oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1022
				oTarget.detachEvent('on' + sEvent, funcHandler);
1023
			};
1024
		}
1025
		else
1026
		{
1027
			oTarget.addEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1028
				oTarget['on' + sEvent] = funcHandler;
1029
			};
1030
1031
			oTarget.removeEventListener = function (sEvent, funcHandler, bCapture) {
0 ignored issues
show
Unused Code introduced by
The parameter bCapture is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter funcHandler is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1032
				oTarget['on' + sEvent] = null;
1033
			};
1034
		}
1035
	}
1036
}
1037
1038
1039
/**
1040
 * This function will retrieve the contents needed for the jump to boxes.
1041
 */
1042
function grabJumpToContent() {
1043
	getXMLDocument(elk_prepareScriptUrl(elk_scripturl) + 'action=xmlhttp;sa=jumpto;xml', onJumpReceived);
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1044
1045
	return false;
1046
}
1047
1048
/**
1049
 * Callback function for loading the jumpto box
1050
 *
1051
 * @param {object} oXMLDoc
1052
 */
1053
function onJumpReceived(oXMLDoc) {
1054
	var aBoardsAndCategories = [],
1055
		i,
1056
		n,
1057
		items = oXMLDoc.getElementsByTagName('elk')[0].getElementsByTagName('item');
1058
1059
	for (i = 0, n = items.length; i < n; i++)
1060
	{
1061
		aBoardsAndCategories[aBoardsAndCategories.length] = {
1062
			id: parseInt(items[i].getAttribute('id')),
1063
			isCategory: items[i].getAttribute('type') === 'category',
1064
			name: items[i].firstChild.nodeValue.removeEntities(),
1065
			is_current: false,
1066
			childLevel: parseInt(items[i].getAttribute('childlevel'))
1067
		};
1068
	}
1069
1070
	for (i = 0, n = aJumpTo.length; i < n; i++)
1071
		aJumpTo[i].fillSelect(aBoardsAndCategories);
1072
}
1073
1074
/**
1075
 * JumpTo class.
1076
 *
1077
 * Passed object of options can contain:
1078
 * sContainerId: container id to place the list in
1079
 * sClassName: class name to assign items added to the dropdown
1080
 * sJumpToTemplate: html template to wrap the %dropdown_list%
1081
 * iCurBoardId: id of the board current active
1082
 * iCurBoardChildLevel: child level of the currently active board
1083
 * sCurBoardName: name of the currently active board
1084
 * sBoardChildLevelIndicator: text/characters used to indent
1085
 * sBoardPrefix: arrow head
1086
 * sCatPrefix: Prefix to use in from of the categories
1087
 * bNoRedirect: boolean for redirect
1088
 * bDisabled: boolean for disabled
1089
 * sCustomName: custom name to prefix for the select name=""
1090
 * sGoButtonLabel: name for the goto button
1091
 *
1092
 * @param {type} oJumpToOptions
1093
 */
1094
// This'll contain all JumpTo objects on the page.
1095
var aJumpTo = [];
1096
function JumpTo(oJumpToOptions)
1097
{
1098
	this.opt = oJumpToOptions;
1099
	this.dropdownList = null;
1100
	this.showSelect();
1101
1102
	createEventListener(this.dropdownList);
1103
1104
	if (is_mobile && is_touch)
1105
		this.dropdownList.addEventListener('touchstart', grabJumpToContent);
1106
	else
1107
		this.dropdownList.addEventListener('mouseenter', grabJumpToContent);
1108
}
1109
1110
// Remove all the options in the select. Method of the JumpTo class.
1111
JumpTo.prototype.removeAll = function ()
1112
{
1113
//	var dropdownList = document.getElementById(this.opt.sContainerId + '_select');
1114
for (var i = this.dropdownList.options.length; i > 0; i--)
1115
		this.dropdownList.remove(i - 1);
1116
};
1117
1118
// Show the initial select box (onload). Method of the JumpTo class.
1119
JumpTo.prototype.showSelect = function ()
1120
{
1121
	var sChildLevelPrefix = '';
1122
1123
	for (var i = this.opt.iCurBoardChildLevel; i > 0; i--)
1124
		sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1125
1126
	if (sChildLevelPrefix !== '')
1127
		sChildLevelPrefix += this.opt.sBoardPrefix;
1128
1129
	document.getElementById(this.opt.sContainerId).innerHTML = this.opt.sJumpToTemplate.replace(/%select_id%/, this.opt.sContainerId + '_select').replace(/%dropdown_list%/, '<select ' + (this.opt.bDisabled === true ? 'disabled="disabled" ' : '') + (this.opt.sClassName !== undefined ? 'class="' + this.opt.sClassName + '" ' : '') + 'name="' + (this.opt.sCustomName !== undefined ? this.opt.sCustomName : this.opt.sContainerId + '_select') + '" id="' + this.opt.sContainerId + '_select"><option value="' + (this.opt.bNoRedirect !== undefined && this.opt.bNoRedirect === true ? this.opt.iCurBoardId : '?board=' + this.opt.iCurBoardId + '.0') + '">' + sChildLevelPrefix + this.opt.sCurBoardName.removeEntities() + '</option></select>&nbsp;' + (this.opt.sGoButtonLabel !== undefined ? '<input type="button" class="button_submit" value="' + this.opt.sGoButtonLabel + '" onclick="window.location.href = \'' + elk_prepareScriptUrl(elk_scripturl) + 'board=' + this.opt.iCurBoardId + '.0\';" />' : ''));
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1130
	this.dropdownList = document.getElementById(this.opt.sContainerId + '_select');
1131
};
1132
1133
// Fill the jump to box with entries. Method of the JumpTo class.
1134
JumpTo.prototype.fillSelect = function (aBoardsAndCategories)
1135
{
1136
	this.removeAll();
1137
1138
	if (is_mobile && is_touch)
1139
		this.dropdownList.removeEventListener('touchstart', grabJumpToContent);
1140
	else
1141
		this.dropdownList.removeEventListener('mouseenter', grabJumpToContent);
1142
1143
	// Create a document fragment that'll allowing inserting big parts at once.
1144
	var oListFragment = document.createDocumentFragment(),
1145
		oOptgroupFragment = document.createElement('optgroup');
1146
1147
	// Loop through all items to be added.
1148
	for (var i = 0, n = aBoardsAndCategories.length; i < n; i++)
1149
	{
1150
		var j,
1151
			sChildLevelPrefix = '',
1152
			oOption,
1153
			oText;
1154
1155
		if (aBoardsAndCategories[i].isCategory)
1156
		{
1157
			oOptgroupFragment = document.createElement('optgroup');
1158
			oOptgroupFragment.label = aBoardsAndCategories[i].name;
1159
			oListFragment.appendChild(oOptgroupFragment);
1160
			continue;
1161
		}
1162
		else
1163
		{
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
1164
			for (j = aBoardsAndCategories[i].childLevel, sChildLevelPrefix = ''; j > 0; j--)
1165
				sChildLevelPrefix += this.opt.sBoardChildLevelIndicator;
1166
1167
			if (sChildLevelPrefix !== '')
1168
				sChildLevelPrefix += this.opt.sBoardPrefix;
1169
		}
1170
1171
		oOption = document.createElement('option');
1172
		oText = document.createElement('span');
1173
		oText.innerHTML = sChildLevelPrefix + aBoardsAndCategories[i].name;
1174
1175
		if (aBoardsAndCategories[i].id === this.opt.iCurBoardId)
1176
			oOption.selected = 'selected';
1177
1178
		oOption.appendChild(oText);
1179
1180
		if (!this.opt.bNoRedirect)
1181
		{
1182
			oOption.value = '?board=' + aBoardsAndCategories[i].id + '.0';
1183
		}
1184
		else
1185
		{
1186
			oOption.value = aBoardsAndCategories[i].id;
1187
		}
1188
1189
		oOptgroupFragment.appendChild(oOption);
1190
	}
1191
1192
	// Add the remaining items after the currently selected item.
1193
	this.dropdownList.appendChild(oListFragment);
1194
1195
	// Add an onchange action
1196
	if (!this.opt.bNoRedirect)
1197
		this.dropdownList.onchange = function() {
1198
			if (this.selectedIndex > 0 && this.options[this.selectedIndex].value)
1199
				window.location.href = elk_scripturl + this.options[this.selectedIndex].value.substr(elk_scripturl.indexOf('?') === -1 || this.options[this.selectedIndex].value.substr(0, 1) !== '?' ? 0 : 1);
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1200
		};
1201
1202
	// Handle custom function hook before showing the new select.
1203
	if ('funcOnBeforeCollapse' in this.opt)
1204
	{
1205
		this.tmpMethod = this.opt.funcOnBeforeCollapse;
1206
		this.tmpMethod(this);
1207
		delete this.tmpMethod;
1208
	}
1209
};
1210
1211
/**
1212
 * IconList object.
1213
 *
1214
 * Allows clicking on a icon to expand out the available options to change
1215
 * Change is done via ajax
1216
 * Used for topic icon and member group icon selections
1217
 *
1218
 * Available options
1219
 *	sBackReference:
1220
 *	sIconIdPrefix:
1221
 *	bShowModify:
1222
 *	iBoardId:
1223
 *	iTopicId:
1224
 *	sAction:
1225
 *	sLabelIconList:
1226
 *
1227
 * The following are style elements that can be passed
1228
 *	sBoxBackground:
1229
 *	sBoxBackgroundHover:
1230
 *	iBoxBorderWidthHover:
1231
 *	sBoxBorderColorHover:
1232
 *	sContainerBackground:
1233
 *	sContainerBorder:
1234
 *	sItemBorder:
1235
 *	sItemBorderHover:
1236
 *	sItemBackground:
1237
 *	sItemBackgroundHover:
1238
 *
1239
 * @param {object} oOptions
1240
 */
1241
// A global array containing all IconList objects.
1242
var aIconLists = [];
1243
function IconList(oOptions)
1244
{
1245
	this.opt = oOptions;
1246
	this.bListLoaded = false;
1247
	this.oContainerDiv = null;
1248
	this.funcMousedownHandler = null;
1249
	this.funcParent = this;
1250
	this.iCurMessageId = 0;
1251
	this.iCurTimeout = 0;
1252
1253
	// Set a default Action
1254
	if (!('sAction' in this.opt) || this.opt.sAction === null)
1255
		this.opt.sAction = 'messageicons;board=' + this.opt.iBoardId;
1256
1257
	this.initIcons();
1258
}
1259
1260
// Replace all message icons by icons with hoverable and clickable div's.
1261
IconList.prototype.initIcons = function ()
1262
{
1263
	for (var i = document.images.length - 1, iPrefixLength = this.opt.sIconIdPrefix.length; i >= 0; i--)
1264
		if (document.images[i].id.substr(0, iPrefixLength) === this.opt.sIconIdPrefix)
1265
			setOuterHTML(document.images[i], '<div title="' + this.opt.sLabelIconList + '" onclick="' + this.opt.sBackReference + '.openPopup(this, ' + document.images[i].id.substr(iPrefixLength) + ')" onmouseover="' + this.opt.sBackReference + '.onBoxHover(this, true)" onmouseout="' + this.opt.sBackReference + '.onBoxHover(this, false)" style="background: ' + this.opt.sBoxBackground + '; cursor: pointer; padding: 2px; margin: 0 auto; vertical-align: top"><img src="' + document.images[i].src + '" alt="' + document.images[i].alt + '" id="' + document.images[i].id + '" style="vertical-align: top; margin: 0 auto; padding: 0 2px;" /></div>');
1266
};
1267
1268
// Event for the mouse hovering over the original icon.
1269
IconList.prototype.onBoxHover = function (oDiv, bMouseOver)
1270
{
1271
	oDiv.style.border = bMouseOver ? this.opt.iBoxBorderWidthHover + 'px solid ' + this.opt.sBoxBorderColorHover : '';
1272
	oDiv.style.background = bMouseOver ? this.opt.sBoxBackgroundHover : this.opt.sBoxBackground;
1273
	oDiv.style.padding = bMouseOver ? (2 - this.opt.iBoxBorderWidthHover) + 'px' : '2px';
1274
};
1275
1276
// Show the list of icons after the user clicked the original icon.
1277
IconList.prototype.openPopup = function (oDiv, iMessageId)
1278
{
1279
	this.iCurMessageId = iMessageId;
1280
1281
	if (!this.bListLoaded && this.oContainerDiv === null)
1282
	{
1283
		// Create a container div.
1284
		this.oContainerDiv = document.createElement('div');
1285
		this.oContainerDiv.id = 'iconList';
1286
		this.oContainerDiv.style.display = 'none';
1287
		this.oContainerDiv.style.cursor = 'pointer';
1288
		this.oContainerDiv.style.position = 'absolute';
1289
		this.oContainerDiv.style.background = this.opt.sContainerBackground;
1290
		this.oContainerDiv.style.border = this.opt.sContainerBorder;
1291
		this.oContainerDiv.style.padding = '6px 0px';
1292
		document.body.appendChild(this.oContainerDiv);
1293
1294
		// Start to fetch its contents.
1295
		ajax_indicator(true);
1296
		sendXMLDocument.call(this, elk_prepareScriptUrl(elk_scripturl) + 'action=xmlhttp;sa=' + this.opt.sAction + ';xml', '', this.onIconsReceived);
0 ignored issues
show
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1297
1298
		createEventListener(document.body);
1299
	}
1300
1301
	// Set the position of the container.
1302
	var aPos = elk_itemPos(oDiv);
1303
1304
	this.oContainerDiv.style.top = (aPos[1] + oDiv.offsetHeight) + 'px';
1305
	this.oContainerDiv.style.left = (aPos[0] - 1) + 'px';
1306
	this.oClickedIcon = oDiv;
1307
1308
	if (this.bListLoaded)
1309
		this.oContainerDiv.style.display = 'block';
1310
1311
	document.body.addEventListener('mousedown', this.onWindowMouseDown, false);
1312
};
1313
1314
// Setup the list of icons once it is received through xmlHTTP.
1315
IconList.prototype.onIconsReceived = function (oXMLDoc)
1316
{
1317
	var icons = oXMLDoc.getElementsByTagName('elk')[0].getElementsByTagName('icon'),
1318
		sItems = '';
1319
1320
	for (var i = 0, n = icons.length; i < n; i++)
1321
		sItems += '<span onmouseover="' + this.opt.sBackReference + '.onItemHover(this, true)" onmouseout="' + this.opt.sBackReference + '.onItemHover(this, false);" onmousedown="' + this.opt.sBackReference + '.onItemMouseDown(this, \'' + icons[i].getAttribute('value') + '\');" style="padding: 2px 3px; line-height: 20px; border: ' + this.opt.sItemBorder + '; background: ' + this.opt.sItemBackground + '"><img src="' + icons[i].getAttribute('url') + '" alt="' + icons[i].getAttribute('name') + '" title="' + icons[i].firstChild.nodeValue + '" style="vertical-align: middle" /></span>';
1322
1323
	this.oContainerDiv.innerHTML = sItems;
1324
	this.oContainerDiv.style.display = 'block';
1325
	this.bListLoaded = true;
1326
1327
	if (is_ie)
1328
		this.oContainerDiv.style.width = this.oContainerDiv.clientWidth + 'px';
1329
1330
	ajax_indicator(false);
1331
};
1332
1333
// Event handler for hovering over the icons.
1334
IconList.prototype.onItemHover = function (oDiv, bMouseOver)
1335
{
1336
	oDiv.style.background = bMouseOver ? this.opt.sItemBackgroundHover : this.opt.sItemBackground;
1337
	oDiv.style.border = bMouseOver ? this.opt.sItemBorderHover : this.opt.sItemBorder;
1338
1339
	if (this.iCurTimeout !== 0)
1340
		window.clearTimeout(this.iCurTimeout);
1341
1342
	if (bMouseOver)
1343
		this.onBoxHover(this.oClickedIcon, true);
1344
	else
1345
		this.iCurTimeout = window.setTimeout(this.opt.sBackReference + '.collapseList();', 500);
1346
};
1347
1348
// Event handler for clicking on one of the icons.
1349
IconList.prototype.onItemMouseDown = function (oDiv, sNewIcon)
1350
{
1351
	if (this.iCurMessageId !== 0)
1352
	{
1353
		ajax_indicator(true);
1354
		this.tmpMethod = getXMLDocument;
1355
		var oXMLDoc = this.tmpMethod(elk_prepareScriptUrl(elk_scripturl) + 'action=jsmodify;topic=' + this.opt.iTopicId + ';msg=' + this.iCurMessageId + ';' + elk_session_var + '=' + elk_session_id + ';icon=' + sNewIcon + ';xml');
0 ignored issues
show
Bug introduced by
The variable elk_session_id seems to be never declared. If this is a global, consider adding a /** global: elk_session_id */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_session_var seems to be never declared. If this is a global, consider adding a /** global: elk_session_var */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable elk_scripturl seems to be never declared. If this is a global, consider adding a /** global: elk_scripturl */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1356
		delete this.tmpMethod;
1357
		ajax_indicator(false);
1358
1359
		var oMessage = oXMLDoc.responseXML.getElementsByTagName('elk')[0].getElementsByTagName('message')[0];
1360
		if (oMessage.getElementsByTagName('error').length === 0)
1361
		{
1362
			if ((this.opt.bShowModify && oMessage.getElementsByTagName('modified').length !== 0) && (document.getElementById('modified_' + this.iCurMessageId) !== null))
1363
				document.getElementById('modified_' + this.iCurMessageId).innerHTML = oMessage.getElementsByTagName('modified')[0].childNodes[0].nodeValue;
1364
1365
			this.oClickedIcon.getElementsByTagName('img')[0].src = oDiv.getElementsByTagName('img')[0].src;
1366
		}
1367
	}
1368
	else
1369
	{
1370
		this.oClickedIcon.getElementsByTagName('img')[0].src = oDiv.getElementsByTagName('img')[0].src;
1371
		if ('sLabelIconBox' in this.opt)
1372
			document.getElementById(this.opt.sLabelIconBox).value = sNewIcon;
1373
	}
1374
};
1375
1376
// Event handler for clicking outside the list (will make the list disappear).
1377
IconList.prototype.onWindowMouseDown = function ()
1378
{
1379
	for (var i = aIconLists.length - 1; i >= 0; i--)
1380
	{
1381
		aIconLists[i].funcParent.tmpMethod = aIconLists[i].collapseList;
1382
		aIconLists[i].funcParent.tmpMethod();
1383
		delete aIconLists[i].funcParent.tmpMethod;
1384
	}
1385
};
1386
1387
// Collapse the list of icons.
1388
IconList.prototype.collapseList = function()
1389
{
1390
	this.onBoxHover(this.oClickedIcon, false);
1391
	this.oContainerDiv.style.display = 'none';
1392
	this.iCurMessageId = 0;
1393
	document.body.removeEventListener('mousedown', this.onWindowMouseDown, false);
1394
};
1395
1396
/**
1397
 * Short function for finding the actual screen position of an item.
1398
 * Used for example to position the suggest member name box
1399
 *
1400
 * @param {object} itemHandle
1401
 */
1402
function elk_itemPos(itemHandle)
1403
{
1404
	var itemX = 0,
1405
		itemY = 0;
1406
1407
	if ('offsetParent' in itemHandle)
1408
	{
1409
		itemX = itemHandle.offsetLeft;
1410
		itemY = itemHandle.offsetTop;
1411
1412
		while (itemHandle.offsetParent && typeof(itemHandle.offsetParent) === 'object')
1413
		{
1414
			itemHandle = itemHandle.offsetParent;
1415
			itemX += itemHandle.offsetLeft;
1416
			itemY += itemHandle.offsetTop;
1417
		}
1418
	}
1419
	else if ('x' in itemHandle)
1420
	{
1421
		itemX = itemHandle.x;
1422
		itemY = itemHandle.y;
1423
	}
1424
1425
	return [itemX, itemY];
1426
}
1427
1428
/**
1429
 * This function takes the script URL and prepares it to allow the query string to be appended to it.
1430
 *
1431
 * @param {string} sUrl
1432
 */
1433
function elk_prepareScriptUrl(sUrl)
1434
{
1435
	return sUrl.indexOf('?') === -1 ? sUrl + '?' : sUrl + (sUrl.charAt(sUrl.length - 1) === '?' || sUrl.charAt(sUrl.length - 1) === '&' || sUrl.charAt(sUrl.length - 1) === ';' ? '' : ';');
1436
}
1437
1438
/**
1439
 * Load Event function, adds new events to the window onload control
1440
 *
1441
 * @param {object} fNewOnload function object or string to call
1442
 */
1443
var aOnloadEvents = [];
1444
function addLoadEvent(fNewOnload)
1445
{
1446
	// If there's no event set, just set this one
1447
	if (typeof(fNewOnload) === 'function' && (!('onload' in window) || typeof(window.onload) !== 'function'))
1448
		window.onload = fNewOnload;
1449
	// If there's just one event, setup the array.
1450
	else if (aOnloadEvents.length === 0)
1451
	{
1452
		aOnloadEvents[0] = window.onload;
1453
		aOnloadEvents[1] = fNewOnload;
1454
		window.onload = function() {
1455
			for (var i = 0, n = aOnloadEvents.length; i < n; i++)
1456
			{
1457
				if (typeof(aOnloadEvents[i]) === 'function')
1458
					aOnloadEvents[i]();
1459
				else if (typeof(aOnloadEvents[i]) === 'string')
1460
					eval(aOnloadEvents[i]);
0 ignored issues
show
Security Performance introduced by
Calls to eval are slow and potentially dangerous, especially on untrusted code. Please consider whether there is another way to achieve your goal.
Loading history...
Coding Style Security introduced by
The use of eval is generally not recommended.

The use of eval is discouraged because it can potentially make your code vulnerable to various injection attacks.

Besides it will also prevent certain optimizations that runtimes otherwise could make.

Loading history...
1461
			}
1462
		};
1463
	}
1464
	// This isn't the first event function, add it to the list.
1465
	else
1466
		aOnloadEvents[aOnloadEvents.length] = fNewOnload;
1467
}
1468
1469
/**
1470
 * Get the text in a code tag by selecting the [select] in the code header
1471
 *
1472
 * @param {object} oCurElement
1473
 * @param {boolean} bActOnElement the passed element contains the code
1474
 */
1475
function elkSelectText(oCurElement, bActOnElement)
1476
{
1477
	var oCodeArea = null;
0 ignored issues
show
Unused Code introduced by
The assignment to oCodeArea seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
1478
1479
	// The place we're looking for is one div up, and next door - if it's auto detect.
1480
	if (typeof(bActOnElement) === 'boolean' && bActOnElement)
1481
		oCodeArea = document.getElementById(oCurElement);
1482
	else
1483
		oCodeArea = oCurElement.parentNode.nextSibling;
1484
1485
	// Did not find it, bail
1486
	if (typeof(oCodeArea) !== 'object' || oCodeArea === null)
1487
		return false;
1488
1489
	// Start off with internet explorer < 9.
1490
	if ('createTextRange' in document.body)
1491
	{
1492
		var oCurRange = document.body.createTextRange();
1493
		oCurRange.moveToElementText(oCodeArea);
1494
		oCurRange.select();
1495
	}
1496
	// All the rest
1497
	else if (window.getSelection)
1498
	{
1499
		var oCurSelection = window.getSelection(),
1500
			curRange = document.createRange();
1501
1502
			curRange.selectNodeContents(oCodeArea);
1503
			oCurSelection.removeAllRanges();
1504
			oCurSelection.addRange(curRange);
1505
	}
1506
1507
	return false;
1508
}
1509
1510
/**
1511
 * A function needed to discern HTML entities from non-western characters.
1512
 *
1513
 * @param {string} sFormName
1514
 * @param {Array.} aElementNames
1515
 * @param {string} sMask
1516
 */
1517
function smc_saveEntities(sFormName, aElementNames, sMask) {
1518
	var i = 0,
1519
		n = 0;
1520
1521
	if (typeof(sMask) === 'string') {
1522
		for (i = 0, n = document.forms[sFormName].elements.length; i < n; i++) {
1523
			if (document.forms[sFormName].elements[i].id.substr(0, sMask.length) === sMask) {
1524
				aElementNames[aElementNames.length] = document.forms[sFormName].elements[i].name;
1525
			}
1526
		}
1527
	}
1528
1529
	for (i = 0, n = aElementNames.length; i < n; i++) {
1530
		if (aElementNames[i] in document.forms[sFormName]) {
1531
			// Handle the editor.
1532
			if (typeof post_box_name !== 'undefined' && aElementNames[i] === post_box_name && $editor_data[post_box_name] !== undefined) {
0 ignored issues
show
Bug introduced by
The variable post_box_name seems to be never declared. If this is a global, consider adding a /** global: post_box_name */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable $editor_data seems to be never declared. If this is a global, consider adding a /** global: $editor_data */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1533
				document.forms[sFormName][aElementNames[i]].value = $editor_data[post_box_name].val().replace(/&#/g, '&#38;#');
1534
				$editor_data[post_box_name].val(document.forms[sFormName][aElementNames[i]].value);
1535
			}
1536
			else {
1537
				document.forms[sFormName][aElementNames[i]].value = document.forms[sFormName][aElementNames[i]].value.replace(/&#/g, '&#38;#');
1538
			}
1539
		}
1540
	}
1541
}
1542
1543
/**
1544
 * Enable / Disable the "Only show the results after the poll has expired."
1545
 * based on if they have entered a time limit or not
1546
 *
1547
 * @returns {undefined}
1548
 */
1549
function pollOptions()
1550
{
1551
	var expire_time = document.getElementById('poll_expire');
1552
1553
	if (isEmptyText(expire_time) || expire_time.value === 0)
1554
	{
1555
		document.forms[form_name].poll_hide[2].disabled = true;
0 ignored issues
show
Bug introduced by
The variable form_name seems to be never declared. If this is a global, consider adding a /** global: form_name */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1556
		if (document.forms[form_name].poll_hide[2].checked)
1557
			document.forms[form_name].poll_hide[1].checked = true;
1558
	}
1559
	else
1560
		document.forms[form_name].poll_hide[2].disabled = false;
1561
}
1562
1563
/**
1564
 * Generate the number of days in a given month for a given year
1565
 * Used to populate the day pulldown in the calendar
1566
 *
1567
 * @param {int} [offset] optional
1568
 */
1569
function generateDays(offset)
1570
{
1571
	// Work around JavaScript's lack of support for default values...
1572
	offset = typeof(offset) !== 'undefined' ? offset : '';
1573
1574
	var days = 0,
1575
		selected = 0,
1576
		dayElement = document.getElementById("day" + offset),
1577
		yearElement = document.getElementById("year" + offset),
1578
		monthElement = document.getElementById("month" + offset),
1579
		monthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1580
1581
	monthLength[1] = 28;
1582
	if (yearElement.options[yearElement.selectedIndex].value % 4 === 0)
1583
		monthLength[1] = 29;
1584
1585
	selected = dayElement.selectedIndex;
1586
	while (dayElement.options.length)
1587
		dayElement.options[0] = null;
1588
1589
	days = monthLength[monthElement.value - 1];
1590
1591
	for (var i = 1; i <= days; i++)
1592
		dayElement.options[dayElement.length] = new Option(i, i);
0 ignored issues
show
Bug introduced by
The variable Option seems to be never declared. If this is a global, consider adding a /** global: Option */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1593
1594
	if (selected < days)
1595
		dayElement.selectedIndex = selected;
1596
}
1597
1598
/**
1599
 * Enable/disable the board selection list when a calendar event is linked, or not, to a post
1600
 *
1601
 * @param {string} form
1602
 */
1603
function toggleLinked(form)
1604
{
1605
	form.board.disabled = !form.link_to_board.checked;
1606
}
1607
1608
/**
1609
 * load event for search for and PM search, un escapes any existing search
1610
 * value for back button or change search etc.
1611
 */
1612
function initSearch()
1613
{
1614
	if (document.forms.searchform.search.value.indexOf("%u") !== -1)
1615
		document.forms.searchform.search.value = decodeURI(document.forms.searchform.search.value);
1616
}
1617
1618
/**
1619
 * Checks or unchecks the list of available boards
1620
 *
1621
 * @param {type} ids
1622
 * @param {string} aFormName
1623
 * @param {string} sInputName
1624
 */
1625
function selectBoards(ids, aFormName, sInputName)
1626
{
1627
	var toggle = true,
1628
		i = 0;
1629
1630
	for (var f = 0, max = document.forms.length; f < max; f++)
1631
	{
1632
		if (document.forms[f].name == aFormName)
1633
		{
1634
			aForm = document.forms[f];
0 ignored issues
show
Bug introduced by
The variable aForm seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.aForm.
Loading history...
1635
			break;
1636
		}
1637
	}
1638
	if (typeof aForm == 'undefined')
1639
		return;
1640
1641
	for (i = 0; i < ids.length; i++)
1642
		toggle = toggle && aForm[sInputName + '[' + ids[i] + ']'].checked;
1643
1644
	for (i = 0; i < ids.length; i++)
1645
		aForm[sInputName + '[' + ids[i] + ']'].checked = !toggle;
1646
}
1647
1648
/**
1649
 * Expands or collapses a container
1650
 *
1651
 * @param {string} id
1652
 * @param {string} icon
1653
 * @param {int} speed
1654
 */
1655
function expandCollapse(id, icon, speed)
1656
{
1657
	var	oId = $('#' + id);
1658
1659
	icon = icon || false;
1660
	speed = speed || 300;
1661
1662
	// Change the icon on the box as well?
1663
	if (icon)
1664
		$('#' + icon).attr("src", elk_images_url + (oId.is(":hidden") !== true ? "/selected.png" : "/selected_open.png"));
0 ignored issues
show
Bug introduced by
The variable elk_images_url seems to be never declared. If this is a global, consider adding a /** global: elk_images_url */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1665
1666
	// Open or collapse the content id
1667
	oId.slideToggle(speed);
1668
}
1669
1670
/**
1671
 * Highlight a selection box by adding the highlight2 class
1672
 *
1673
 * @param {string} container_id
1674
 */
1675
function initHighlightSelection(container_id)
1676
{
1677
	$('#' + container_id + ' [name="def_language"]').on('click', function (ev) {
0 ignored issues
show
Unused Code introduced by
The parameter ev is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1678
		$('#' + container_id + ' .standard_row').removeClass('highlight2');
1679
		$(this).parent().parent().addClass('highlight2');
1680
	});
1681
}
1682
1683
/**
1684
 * Auto submits a paused form, such as a maintenance task
1685
 *
1686
 * @param {int} countdown
1687
 * @param {string} txt_message
1688
 * @param {string} [formName=autoSubmit]
0 ignored issues
show
Documentation Bug introduced by
The parameter formName=autoSubmit does not exist. Did you maybe mean formName instead?
Loading history...
1689
 */
1690
function doAutoSubmit(countdown, txt_message, formName)
1691
{
1692
	var formID = typeof(formName) !== 'undefined' ? formName : "autoSubmit";
1693
1694
	if (countdown === 0)
1695
		document.forms[formID].submit();
1696
	else if (countdown === -1)
1697
		return;
1698
1699
	document.forms[formID].cont.value = txt_message + ' (' + countdown + ')';
1700
	countdown--;
1701
1702
	setTimeout(function() {doAutoSubmit(countdown, txt_message, formID);}, 1000);
1703
}
1704